from base import BitsLong
from base.exception.IllegalArgumentException import IllegalArgumentException


# Exponent: returns -1 for out of inline range.
#param long
# return long
def encode11to9(exp11):
    if (exp11 == 0):
        return 0
    if (exp11 == 0x7FF):
        return 0x3FF

    # Remove bias.
    expRebase = exp11 - 1023
    if (expRebase < -254 or expRebase > 255):
        # Out of range.
        return -1
    exp9 = expRebase + 255
    return exp9

# Exponent
#param long
# return long
def decode9to11(exp9):
    if (exp9 == 0):
        return 0
    elif (exp9 == 0x1FF):
        return 0x7FF
    expRebase = exp9 - 255
    exp11 = expRebase + 1023
    return exp11


'''
 * Encode as a 62 bit long.
 * Return:@link #NO_ENCODING for "not possible".
 * The top two bits are zero if packing was possible.
 '''
#param double
# return long
def pack(v):
    # Not "raw" , so NaNs end up as the same bit pattern when packed.
    # TODO
    # x = Double.doubleToLongBits(v)
    x = v
    sign = BitsLong.unpack(x, 63, 64)
    exp11 = BitsLong.unpack(x, 52, 63)
    exp9 = encode11to9(exp11)
    if (exp9 == -1):
        return NO_ENCODING
    significand = BitsLong.unpack(x, 0, 52)
    # Do not set the value bit or double bit.
    # This is done in NodeId.toBytes and NodeId.toByteBuffer.
    z = 0
    z = BitsLong.pack(z, sign, 61, 62)
    z = BitsLong.pack(z, exp9, 52, 61)
    z = BitsLong.pack(z, significand, 0, 52)
    return z

#param long
# return double
def unpack(x):
    if (x == NO_ENCODING):
        raise IllegalArgumentException("No encoding inline")
    sign = BitsLong.unpack(x, 61, 62)
    exp9 = BitsLong.unpack(x, 52, 61)
    significand = BitsLong.unpack(x, 0, 52)
    exp11 = decode9to11(exp9)
    z = 0
    z = BitsLong.pack(z, sign, 63, 64)
    z = BitsLong.pack(z, exp11, 52, 63)
    z = BitsLong.pack(z, significand, 0, 52)
    # TODO
    # d = Double.longBitsToDouble(z)
    d = z
    return d

'''
 * An encoded value that is not possible.
 * (it has high bits set).
 '''
NO_ENCODING = 0xFF00_0000_0000_0000
'''
 * 0x1ff0000000000000L
 *
 * @see Double#POSITIVE_INFINITY
 '''
# long
POSITIVE_INFINITY_BITS = 0x1ff0000000000000
'''
 * @see Double#POSITIVE_INFINITY
 '''
# double
POSITIVE_INFINITY = unpack(POSITIVE_INFINITY_BITS)
'''
 * 0x3ff0000000000000L
 *
 * @see Double#NEGATIVE_INFINITY
 '''
# long
NEGATIVE_INFINITY_BITS = 0x3ff0000000000000
'''
 * @see Double#NEGATIVE_INFINITY
 '''
# double
NEGATIVE_INFINITY = unpack(NEGATIVE_INFINITY_BITS)
'''
 * 0x1ff8000000000000L
 *
 * @see Double#NaN
 '''
# long
NaN_BITS = 0x1ff8000000000000
'''
 * @see Double#NaN
 '''
# double
NaN = unpack(NaN_BITS)

# ---- Constants without type bits (so bits 62 and 63 are zero).
'''
 * 0x3fefffffffffffffL
 * <br/>
 * (2-2<sup>-52</sup>)&middot2<sup>255</sup>.
 *
 * @see Double#MAX_VALUE
 '''
# long
MAX_VALUE_BITS = 0x1fefffffffffffff
'''
 * 0x3fefffffffffffffL
 * <br/>
 * (2-2<sup>-52</sup>)&middot2<sup>255</sup>.
 *
 * @see Double#MAX_VALUE
 '''
# double
MAX_VALUE = unpack(MAX_VALUE_BITS)          # 1.1579208923731618e+77
'''
 * 0x0010000000000000L
 *
 * @see Double#MIN_NORMAL
 '''
# long
MIN_NORMAL_BITS = 0x0010000000000000
'''
 * @see Double#MIN_NORMAL
 '''
# double
MIN_NORMAL = unpack(0x0010000000000000)    # 3.454467422037778e-77
'''
 * 0x01L
 *
 * @see Double#MIN_VALUE
 '''
# long
MIN_VALUE_BITS = 0x01
'''
 * 0x01L
 *
 * @see Double#MIN_VALUE
 '''
# double
MIN_VALUE = unpack(MIN_VALUE_BITS)          # 4.9e-324
'''
 * @see Double#MAX_EXPONENT
 '''
# int
MAX_EXPONENT = 255
'''
 * @see Double#MIN_EXPONENT
 '''
# int
MIN_EXPONENT = -254
'''
 * @see Double#SIZE
 '''
# int
SIZE = 62


#param long
# return long
def insertType(x):
    # bits 63 1 (pointer/value), bit 62 1(double)
    return x | 0x3 << 62


#param long
# return long
def removeType(x):
    # bits 63 1 (pointer/value), bit 62 1(double)
    return x & ~(0x3 << 62)



if __name__ == '__main__':
    print(POSITIVE_INFINITY_BITS)